package sublinear.model.db;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import sublinear.model.AbstractGraph;

public class DbGraph extends AbstractGraph {

	private static final Logger log = Logger.getLogger( DbGraph.class.getName() );

	public DbGraph(DbGraphModel model) {
		this.model = model;
		this.graphNodeCache = new HashMap<Long, GraphNode>();
	}

	@Override
	public ArrayList<GraphNode> getNeighbors(GraphNode node) {
		ArrayList<GraphNode> neighbors = new ArrayList<GraphNode>();
		try
		{
			String title = model.getArticleById(node.getUniqueId());
			log.finest("Looking up neighbors of " + title + " (" + node.getUniqueId() + ")");
			if (title != null) {
				ArrayList<Long> neighborsIds = model.getLinksById(node.getUniqueId());
				for(Long nId : neighborsIds) {
					if (nId != DbGraphModel.UNRESOLVED) {
						GraphNode neighbor = getGraphNode(nId);
						neighbors.add(neighbor);
						log.finest("Found neighbor " + neighbor.getFriendlyName() + " (" + nId + ")");
					}
				}
			}
		}
		catch(SQLException e) 
		{
			log.log(Level.SEVERE, "SQL Exception was thrown: " + e.getMessage(), e);
			// Simply crash
			throw new RuntimeException(e);
		}
		return neighbors;
	}

	@Override
	public GraphNode getRandomNode() {
		try
		{
			GraphNode node = null;
			long randomArticleId = DbGraphModel.UNRESOLVED;

			randomArticleId = model.getRandomArticleIdFast();
			node = getGraphNode(randomArticleId);		
			log.finest("Random node: " + node.getFriendlyName() + " (" + node.getUniqueId() + ")");			

			return node;
		}
		catch(SQLException e) 
		{
			log.log(Level.SEVERE, "SQL Exception was thrown: " + e.getMessage(), e);
			// Simply crash
			throw new RuntimeException(e);
		}		
	}

	@Override
	public long getDegree(GraphNode node) {
		try
		{
			return model.getArticleDegree(node.getUniqueId());
		}
		catch(SQLException e) 
		{
			log.log(Level.SEVERE, "SQL Exception was thrown: " + e.getMessage(), e);
			// Simply crash
			throw new RuntimeException(e);
		}					
	}

	private GraphNode getGraphNode(long id) throws SQLException {
		GraphNode node = null;
		if (!graphNodeCache.containsKey(id)) {
			String title = model.getArticleById(id);
			node = new GraphNode(id, title);
			graphNodeCache.put(id, node);
		} else {
			node = graphNodeCache.get(id);
		}
		return node;
	}


	private DbGraphModel model;
	private HashMap<Long, GraphNode> graphNodeCache;

	@Override
	public long getSize() {
		try {
			return model.getArticlesCount();
		}
		catch(SQLException e) 
		{
			log.log(Level.SEVERE, "SQL Exception was thrown: " + e.getMessage(), e);
			// Simply crash
			throw new RuntimeException(e);
		}			
	}

}
